home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ian & Stuart's Australian Mac 1993 September
/
clonecd
/
September 93.img
/
Archives
/
Fun, Tricks & Hacks
/
Windows
/
Minesweeper.c
next >
Wrap
C/C++ Source or Header
|
1992-06-14
|
9KB
|
452 lines
#include "MSWindows.h"
extern short gSound;
extern WindowPtr gMineWindow;
extern RGBColor gBlack,gWhite,gLtGray,gDkGray;
extern PicHandle gPicts[];
// Game Globals
Rect gGameRect,
gHdrRect,
gFaceRect;
Boolean gRunning,
gMarks = false,
gNewGame;
gEndGame;
short gFace;
unsigned long gStartTime,now,then;
short rows,cols,mines;
unsigned char *pMineField = nil;
unsigned char *pMineView = nil;
short gGameType;
short colrange[] = {12,16,30,16};
short rowrange[] = {12,16,16,16};
short minerange[] = {20,40,99,40};
#pragma segment TheApp
void
NewGame(Boolean resize)
{
short r,c;
Rect bounds;
GetDateTime(&gStartTime);
now = gStartTime;
cols = colrange[gGameType];
rows = rowrange[gGameType];
mines = minerange[gGameType];
if (pMineField) {
DisposPtr(pMineField);
DisposPtr(pMineView);
}
pMineField = NewPtrClear(rows*cols);
pMineView = NewPtrClear(rows*cols);
for (r = 0; r < rows; r++)
for (c = 0; c < cols; c++)
mineview(r,c) = kButtonPict;
SetRect(&bounds,0,0,cols * kBox + 2*kBorder,rows * kBox + kHdrSize + kBorder);
gHdrRect = bounds;
gHdrRect.top = kBorderTop; // skip MSWindow Hdr
gHdrRect.bottom = kHdrSize;
gFaceRect.top = kBorderTop + kInsetLCD;
gFaceRect.bottom = gFaceRect.top + kIconSize;
gFaceRect.left = (gHdrRect.right - kIconSize) / 2;
gFaceRect.right = gFaceRect.left + kIconSize;
gFace = kHappyFace;
gNewGame = true;
gEndGame = false;
gRunning = false;
SetPort(gMineWindow);
CreateGWorld(&bounds);
SizeWindow((WindowPtr)gMineWindow,bounds.right,bounds.bottom,true); // fUpdate
((MSWindowPtr)gMineWindow)->child->portRect = gMineWindow->portRect;
SizeMSWindow(((MSWindowPtr)gMineWindow)->child);
ClipRect(&bounds);
if (resize)
EraseRect(&bounds);
InvalRect(&bounds); // force an update now
}
void
InitGame(short rx,short cx)
{
register short n,r,c,r1,c1,r2,c2;
unsigned long x;
for (r = 0; r < rows; r++)
for (c = 0; c < cols; c++)
minefield(r,c) = 0;
minefield(rx,cx) = kFlag; // flag the original click cell
n = mines;
while (0 < n) {
x = Random();
r1 = x & 0x7FFF;
r = r1 % rows;
r1 = (x >> 8) & 0x7FFF;
c = r1 % cols;
if ((minefield(r,c) & (~kNumMask)) == 0) {
minefield(r,c) = kMine;
r1 = (r == 0) ? 0 : r - 1;
r2 = (r >= rows - 1) ? rows - 1 : r + 1;
for ( ; r1 <= r2; r1++) {
c1 = (c == 0) ? 0 : c - 1;
c2 = (c >= cols - 1) ? cols - 1 : c + 1;
for ( ; c1 <= c2; c1++) {
if (minefield(r1,c1) != kMine)
minefield(r1,c1)++;
}
}
n--;
}
}
minefield(rx,cx) -= kFlag; // unflag the original click cell
GetDateTime(&gStartTime); // start timing the game now
now = gStartTime;
gNewGame = false;
gRunning = true;
}
void
GameTime(void)
{
if (gRunning) {
GetDateTime(&now);
if (now != then) {
SetPort(gMineWindow);
InvalRect(&gHdrRect);
}
}
}
void
DrawGame(BitMap *pixMap)
{
if (gNewGame)
DrawNewMap(pixMap);
else
DrawHdr();
}
unsigned char
minechar(short r,short c)
{
short v;
v = minefield(r,c);
return ((v >= kMine) ? kBombPict: (v & kNumMask) + kNumPict);
}
void
DrawPict(short id,short *x,short *y)
{
PicHandle pict;
Rect box;
if (pict = gPicts[id]) {
SetRect(&box,*x,*y,*x + (*pict)->picFrame.right,*y + (*pict)->picFrame.bottom);
DrawPicture(pict,&box);
*x += (*pict)->picFrame.right;
}
}
void
DrawLCD(short n,short x,short y)
{
short i,j;
unsigned char v;
Str255 text;
NumToString(n,&text);
for (i = 0; i < 3; i++) {
j = text[0] + i - 2;
v = (j > 0) ? text[j] - '0' : 0;
DrawPict(v + kLCDPict,&x,&y);
}
}
void
DrawBevel(Rect *box,short width,RGBColor *topColor,RGBColor *bottomColor)
{
register short i,a,b1,b2;
RGBForeColor(topColor);
PenSize(width,width);
FrameRect(box);
RGBForeColor(bottomColor);
PenNormal();
a = box->bottom-1;
b1 = box->left;
b2 = box->right-1;
for (i = 0; i < width; i++) {
MoveTo(b1++,a);
LineTo(b2--,a--);
}
a = box->right-1;
b1 = box->top;
b2 = box->bottom-1;
for (i = 0; i < width; i++) {
MoveTo(a,b1++);
LineTo(a--,b2--);
}
}
void
DrawFrame(void)
{
short x,y;
Rect box,box1;
box = gMineWindow->portRect;
box.top = kBorderTop; // Header & menu bar
RGBForeColor(&gLtGray);
PaintRect(&box);
DrawBevel(&box,kBorder1,&gWhite,&gDkGray);
InsetRect(&box,kBorder1+kBorder2,kBorder1+kBorder2);
box1 = box;
box1.bottom = box1.top + 2*kBorderLCD + +2* kBorder3h + kHeightLCD;
DrawBevel(&box1,kBorder3h,&gDkGray,&gWhite);
box1 = box;
box1.top = kHdrSize - kBorder3;
DrawBevel(&box1,kBorder3,&gDkGray,&gWhite);
RGBForeColor(&gDkGray);
x = kInsetLCD;
y = kBorderTop + kInsetLCD + kHeightLCD - 1;
MoveTo(x,kBorderTop + kInsetLCD);
LineTo(x,y);
RGBForeColor(&gWhite);
x += 3*kWidthLCD + 1;
MoveTo(x,kBorderTop + kInsetLCD);
LineTo(x,y);
RGBForeColor(&gDkGray);
x = gMineWindow->portRect.right - kInsetLCD - 3*kWidthLCD - 2;
MoveTo(x,kBorderTop + kInsetLCD);
LineTo(x,y);
RGBForeColor(&gWhite);
x += 3*kWidthLCD + 1;
MoveTo(x,kBorderTop + kInsetLCD);
LineTo(x,y);
RGBForeColor(&gBlack);
}
void
DrawHdr(void)
{
DrawCell(gFace,&gFaceRect);
DrawLCD(mines,kInsetLCD + 1,kBorderTop + kInsetLCD);
GetDateTime(&now);
DrawLCD(now - gStartTime,gMineWindow->portRect.right - kInsetLCD - 3*kWidthLCD - 1,
kBorderTop + kInsetLCD);
then = now;
}
void
DrawCell(short id,Rect *box)
{
PicHandle pict;
if (pict = gPicts[id])
DrawPicture(pict,box);
}
void
DrawNewMap(BitMap *pixMap)
{
short r,c;
Rect box,box1;
DrawFrame();
DrawHdr();
SetRect(&box,kBorder,kHdrSize,kBorder+kBox,kHdrSize+kBox);
r = 0;
for (c = 0; c < cols; c++) {
DrawCell(mineview(r,c),&box);
box.left += kBox;
box.right += kBox;
}
box.left = kBorder;
box.right -= kBox;
gGameRect = box;
for (r = 1; r < rows; r++) {
box1 = box;
box.top += kBox;
box.bottom += kBox;
CopyBits(pixMap,pixMap,&box1,&box,srcCopy,nil);
}
gGameRect.bottom = box.bottom;
}
void
DrawMap(void)
{
short r,c;
Rect box;
DrawHdr();
SetRect(&box,kBorder,kHdrSize,kBorder+kBox,kHdrSize+kBox);
for (r = 0; r < rows; r++) {
box.left = kBorder;
box.right = box.left + kBox;
for (c = 0; c < cols; c++) {
DrawCell(mineview(r,c),&box);
box.left += kBox;
box.right += kBox;
}
box.top += kBox;
box.bottom += kBox;
}
}
void
ClickMines(void)
{
short r,c,x,y;
unsigned char v,v1;
Rect box;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
v = minechar(r,c);
if (v == kBombPict)
v1 = v;
else
if (mineview(r,c) == kFlagPict) // misidentified
v1 = kBadPict;
else
v1 = 0;
if (v1 != 0) {
mineview(r,c) = v1;
x = c * kBox + kBorder;
y = r * kBox + kHdrSize;
SetRect(&box,x,y,x + kBox,y + kBox);
DrawCell(v1,&box);
}
}
}
gFace = kSadFace;
gEndGame = true;
}
void
ClickNeighbors(r,c)
{
short r1,c1,r2,c2,x,y;
unsigned char v;
Rect box;
r1 = (r == 0) ? 0 : r - 1;
r2 = (r >= rows - 1) ? rows - 1 : r + 1;
for ( ; r1 <= r2; r1++) {
c1 = (c == 0) ? 0 : c - 1;
c2 = (c >= cols - 1) ? cols - 1 : c + 1;
for ( ; c1 <= c2; c1++) {
v = minechar(r1,c1);
if (mineview(r1,c1) == kButtonPict) { // currently unturned or unflagged
mineview(r1,c1) = v;
x = c1 * kBox + kBorder;
y = r1 * kBox + kHdrSize;
SetRect(&box,x,y,x + kBox,y + kBox);
DrawCell(v,&box);
if (v == kNumPict)
ClickNeighbors(r1,c1);
}
}
}
}
Boolean PtInGame(Point where)
{
return (PtInRect(where,&gGameRect) || PtInRect(where,&gFaceRect));
}
void
ClickGame(Point where,short modifiers)
{
Boolean result = false;
reclick:
while (StillDown()) {
GetMouse(&where);
if (PtInRect(where,&gGameRect) && (!gEndGame))
ClickCell(where,modifiers);
else
if (PtInRect(where,&gFaceRect)) {
DrawCell(kPressedFace,&gFaceRect);
while (StillDown()) {
GetMouse(&where);
if (!PtInRect(where,&gFaceRect)) { // dragged out of the box
DrawCell(gFace,&gFaceRect);
goto reclick; // try again
}
}
NewGame(false);
}
}
}
void
ClickCell(Point where,short modifiers)
{
unsigned char v;
short r,c,x,y;
Rect box;
DrawCell(kOwFace,&gFaceRect);
where.h -= kBorder;
where.v -= kHdrSize;
r = where.v / kBox;
c = where.h / kBox;
x = c * kBox + kBorder;
y = r * kBox + kHdrSize;
SetRect(&box,x,y,x + kBox,y + kBox);
if (mineview(r,c) == kButtonPict)
DrawCell(kEmptyPict,&box);
while (StillDown()) {
GetMouse(&where);
if (!PtInRect(where,&box)) { // dragged out of the box
if (mineview(r,c) == kButtonPict)
DrawCell(kButtonPict,&box);
if (!PtInRect(where,&gGameRect)) // dragged out of the game
DrawCell(gFace,&gFaceRect);
return; // try new box
}
}
if (gNewGame)
InitGame(r,c);
if (mineview(r,c) == kMarkPict) { // was a mark flag
v = kButtonPict;
} else
if (mineview(r,c) == kFlagPict) { // was a bomb flag
mines++;
v = (gMarks) ? kMarkPict : kButtonPict;
} else
if (modifiers) { // any modifier key down
v = kFlagPict;
mines--;
} else { // just a clean click
v = minechar(r,c);
if (v == kBombPict) {
if (gSound) SysBeep(4);
ClickMines();
v = kBoomPict; // we blew up
}
}
mineview(r,c) = v;
DrawCell(v,&box);
if (v == kNumPict) // this cell has no surrounding bombs
ClickNeighbors(r,c);
DrawHdr();
SaveBits(gMineWindow);
gRunning = (mines != 0);
}